package com.example.testplatform.common;

import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.lang.NonNull;

import java.io.IOException;

/**
 * JWT认证过滤器
 */
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) throws ServletException, IOException {
        try {
            // 获取请求头中的Authorization信息
            final String authorizationHeader = request.getHeader(Constants.JWT.TOKEN_HEADER);
            LogUtils.debug(logger, () -> "接收到Authorization头: " + (authorizationHeader != null ? "Bearer ****" : "空"));

            String username = null;
            String jwtToken = null;

            // 检查Authorization头是否存在且以Bearer开头
            if (authorizationHeader != null && authorizationHeader.startsWith(Constants.JWT.TOKEN_PREFIX)) {
                // 提取令牌
                jwtToken = authorizationHeader.substring(7);
                try {
                    // 从令牌中获取用户名
                    username = jwtTokenUtil.getUsernameFromToken(jwtToken);
                    final String finalUsername = username;
                    LogUtils.debug(logger, () -> "从token中提取用户名成功: " + finalUsername);
                } catch (ExpiredJwtException e) {
                    final String requestUri = request.getRequestURI();
                    LogUtils.warn(logger, "JWT令牌已过期: " + e.getMessage());
                    LogUtils.logSecurityEvent(logger, "JWT_TOKEN_EXPIRED", "system", "令牌已过期，请求路径: " + requestUri);
                } catch (UnsupportedJwtException e) {
                    final String requestUri = request.getRequestURI();
                    LogUtils.warn(logger, "不支持的JWT令牌格式: " + e.getMessage());
                    LogUtils.logSecurityEvent(logger, "JWT_TOKEN_UNSUPPORTED", "system", "不支持的令牌格式，请求路径: " + requestUri);
                } catch (MalformedJwtException e) {
                    final String requestUri = request.getRequestURI();
                    LogUtils.warn(logger, "JWT令牌格式错误: " + e.getMessage());
                    LogUtils.logSecurityEvent(logger, "JWT_TOKEN_MALFORMED", "system", "令牌格式错误，请求路径: " + requestUri);
                } catch (SignatureException e) {
                    final String requestUri = request.getRequestURI();
                    LogUtils.warn(logger, "JWT令牌签名无效: " + e.getMessage());
                    LogUtils.logSecurityEvent(logger, "JWT_TOKEN_INVALID_SIGNATURE", "system", "令牌签名无效，请求路径: " + requestUri);
                } catch (IllegalArgumentException e) {
                    final String requestUri = request.getRequestURI();
                    LogUtils.warn(logger, "JWT令牌参数错误: " + e.getMessage());
                    LogUtils.logSecurityEvent(logger, "JWT_TOKEN_ILLEGAL_ARGS", "system", "令牌参数错误，请求路径: " + requestUri);
                } catch (Exception e) {
                    final String requestUri = request.getRequestURI();
                    LogUtils.warn(logger, "JWT令牌解析失败: " + LogUtils.formatException(e));
                    LogUtils.logSecurityEvent(logger, "JWT_TOKEN_PARSE_ERROR", "system", "令牌解析失败，请求路径: " + requestUri);
                }
            }

            // 如果用户名不为空且当前安全上下文中没有认证信息
            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                // 加载用户信息
                UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                final String finalUsername = username;
                LogUtils.debug(logger, () -> "加载用户信息: " + finalUsername);

                // 验证令牌是否有效
                if (jwtTokenUtil.validateToken(jwtToken, username)) {
                    // 创建认证令牌
                    UsernamePasswordAuthenticationToken authenticationToken = 
                            new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                    authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

                    // 设置认证信息到安全上下文
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                    LogUtils.debug(logger, () -> "用户认证成功: " + finalUsername + ", 设置安全上下文");
                } else {
                    final String requestUri = request.getRequestURI();
                    LogUtils.warn(logger, "JWT令牌验证失败: " + username);
                    LogUtils.logSecurityEvent(logger, "JWT_TOKEN_VALIDATION_FAILED", username, "令牌验证失败，请求路径: " + requestUri);
                }
            }
        } catch (Exception e) {
            LogUtils.error(logger, "JWT认证过滤器执行异常: " + LogUtils.formatException(e));
            LogUtils.logSecurityEvent(logger, "JWT_FILTER_EXCEPTION", "system", "认证过滤器异常: " + e.getMessage());
        }

        // 继续过滤链
        filterChain.doFilter(request, response);
    }
}